16 Exos Algorithmes gloutons
Exercice 1⚓︎
-
Programmer l’algorithme suivanten Python puis le tester sur la liste d’objets (vous pouvez compléter la trame proposée ci-dessous). On décide ici d'utiliser les listes ['nom', valeur, poids] pour représenter les objets. On pourrait aussi utiliser des dictionnaires...
- Calculer les rapports
valeur/poidsde chaque objet et, dans la liste, ajouter ce rapport à chaque objet. - Trier la liste par ordre décroissant de rapports.
- Parcourir tous les éléments de la liste et ajouter au sac à dos ceux dont le poids, cumulé au poids des objets déjà dans le sac, est inférieur ou égal à la capacité totale du sac.
- Lorsque la capacité totale est dépassée, cela signifie, soit que le sac est plein, soit que l’objet est trop lourd pour être inséré intégralement dans le sac.
- Dans ce dernier cas, ajouter la fraction de l’objet nécessaire pour atteindre la capacité maximale du sac.
- Retourner la liste finale des objets se trouvant dans le sac ainsi que la valeur totale de ces objets.
- Calculer les rapports
-
Comment être sûr que ce programme termine ?
- Déterminer le nombre d'opérations maximal nécessaire pour résoudre ce problème pour \(n\) objets (c'est la complexité temporelle de ce programme).
- Déterminer la place nécessaire en mémoire pour résoudre ce problème pour \(n\) objets (c'est la complexité en mémoire de ce programme).
🐍 Script Python
def sac_a_dos_frac(poidsmax, objets):
"""
Cette fonction renvoie la liste des objets correspondant à la valeur maximale
et ne dépassant pas le poids maximal que peut supporter le sac.
Paramètres :
poidsmax (int ou float) : le poids maximal que peut supporter le sac à dos
objets : une liste d'objets
chaque objet est un dictionnaire, avec un nom, une valeur, une masse
Renvoie :
la liste des objets dérobés par le voleur
et la valeur totale correspondante
"""
assert type(poidsmax) == int or type(poidsmax) == float, "Le poids maximal du sac à dos doit être un nombre"
assert type(objets) == list, "Entrer les objets sous forme d'une liste de dictionnaires [['nom': objet 1, 'valeur': valeur1, 'masse': poids1], etc]"
# on fait une copie de la liste d'objets pour ne pas modifier la liste d'origine
objets_copie = objets.copy()
# on calcule le rapport (valeur/poids) pour chaque objet et on met à jour la liste d'objets en lui ajoutant cette nouvelle donnée 'rapport'
for objet in objets_copie:
#... À compléter
objet['rapport'] = rapport
# on range cette liste par ordre décroissant des rapports
objets_copie.sort(key = lambda x: x['rapport'], reverse = True)
# on initialise trois variables
masse_actuelle = 0 # représente la masse du sac après insertion d'un nouvel objet
valeur_actuelle = 0 # représente la valeur contenue dans le sac après insertion d'un nouvel objet
solution = [] # représente la liste des objets insérés dans le sac
# on parcourt un par un les objets de la liste triée
for objet in objets_copie:
if masse_actuelle + objet['masse'] <= poidsmax: # on teste si le nouvel objet a une masse lui permettant d'être inséré dans le sac à dos
#... À compléter # si c'est le cas, on met à jour la masse du sac
#... À compléter # on met à jour la valeur totale
#... À compléter # et on l'insère dans le sac
else: # la masse du nouvel objet dépasse la masse encore disponible : on va en prendre une fraction pour atteindre exactement la masse maximale du sac
masse_frac_dernier_objet = #... À compléter
valeur_frac_dernier_objet = #... À compléter
valeur_actuelle += #... À compléter
masse_actuelle += #... À compléter
solution.append({'nom': f"{(poidsmax - masse_actuelle) / objet['masse']} de {objet['nom']}", 'valeur': valeur_frac_dernier_objet, 'masse': masse_frac_dernier_objet, 'rapport': objet['rapport']})
# Si le sac à dos est plein, on ne passe pas à l'objet suivant, on retourne le résultat immédiatement
if masse_actuelle == poidsmax:
return solution, valeur_actuelle
# on renvoie la liste des objets dérobés par le voleur et la valeur totale correspondante
return solution, valeur_actuelle
# Testons notre fonction sur l'exemple du cours
p = 30
OBJETS = [{"nom": "A", "valeur": 700, "masse": 13},
{"nom": "B", "valeur": 400, "masse": 12},
{"nom": "C", "valeur": 300, "masse": 6},
{"nom": "D", "valeur": 300, "masse": 10},
{"nom": "E", "valeur": 500, "masse": 12},
{"nom": "F", "valeur": 200, "masse": 14}]
objets_derobes, valeur_derobee = sac_a_dos_frac(p, OBJETS)
print("La liste des objets dérobés est la suivante : \n" + str(objets_derobes))
print("Pour une valeur total de : " + "{:,}".format(valeur_derobee).replace(',', ' ') + " euros.")
Exercice 2⚓︎
- Adapter le programme ci-dessus à la variante entière du problème du sac à dos (on pourra compléter la trame proposée ci-dessous).
- Quelle solution nous donne-t-il sur l’exemple précédent ?
- Le tester pour la liste d’objets
[['A', 165, 3], ['B', 100, 2], ['C', 100, 2]]et un poids maximal de \(4\) kg. La solution renvoyée est-elle optimale ?
🐍 Script Python
def sac_a_dos_0_1(poidsmax, objets):
for objet in objets:
#... À compléter
#... À compléter
objets_copie.sort(key = lambda x: x['rapport'], reverse = True)
masse_actuelle = 0 # représente la masse du sac après insertion d'un nouvel objet
valeur_actuelle = 0 # représente la valeur contenue dans le sac après insertion d'un nouvel objet
solution = [] # représente la liste des objets insérés dans le sac
for objet in objets:
if #... À compléter:
#... À compléter
#... À compléter
#... À compléter
return solution, valeur_actuelle
# Testons notre fonction sur l'exemple du cours
print("Exemple du cours : ")
p = 30
objets = [{"nom": "A", "valeur": 700, "masse": 13},
{"nom": "B", "valeur": 400, "masse": 12},
{"nom": "C", "valeur": 300, "masse": 6},
{"nom": "D", "valeur": 300, "masse": 10},
{"nom": "E", "valeur": 500, "masse": 12},
{"nom": "F", "valeur": 200, "masse": 14}]
objets_derobes, valeur_derobee = sac_a_dos_0_1(p, objets)
print("La liste des objets dérobés est la suivante : \n" + str(objets_derobes))
print("Pour une valeur total de : " + "{:,}".format(valeur_derobee).replace(',', ' ') + " euros.")
# Testons notre fonction sur l'exemple de la question 3
print("Exemple de la question 3 : ")
p = 4
objets = [{'nom': 'A', 'valeur': 165, 'masse': 3},
{'nom': 'B', 'valeur': 100, 'masse': 2},
{'nom': 'C', 'valeur': 100, 'masse': 2}]
objets_derobes, valeur_derobee = sac_a_dos_0_1(p, objets)
print("La liste des objets dérobés est la suivante : \n" + str(objets_derobes))
print("Pour une valeur total de : " + "{:,}".format(valeur_derobee).replace(',', ' ') + " euros.")